package com.googlecode.afdbaccess.config.webconfig;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.log4j.Logger;

import com.googlecode.afdbaccess.cache.connectionpool.interfaces.ConnectionPoolFactory;
import com.googlecode.afdbaccess.cache.exceptions.DataLayerException;


public class ReadConfiguration {
  private final static Logger log = Logger.getLogger(ReadConfiguration.class);
    
  private static final String POOL_ENV_URL="java:comp/env/";

  private static Object appServerLookup(Context context, String envUrl, String key) throws NamingException {
    Object returnObject = null;

    try {
      log.debug("Trying to get key (" + key + "). Thread: " + Thread.currentThread());
      returnObject = context.lookup(key);
      log.debug("Found key " + key + " (" + returnObject + "). Thread: " + Thread.currentThread());
    } catch (NamingException exception) {
      try {
        log.debug("Failed. Trying to get key (" + envUrl + key + ") instead. Thread: " + Thread.currentThread());
        returnObject = context.lookup(envUrl + key);
        log.debug("Found key " + envUrl + key + " (" + returnObject + "). Thread: " + Thread.currentThread());
      } catch (NamingException exception2) {
        throw new NamingException("Couldn't find key \"" + key + "\" or key \"" + envUrl + key + "\". Check appserver configuration.");
      }
    }

    return returnObject;
  }

  public static ConnectionPoolFactory instanciatePoolFactory() throws DataLayerException {
    log.debug("Initializing context, Thread: " + Thread.currentThread());

    String poolClass = "";
    try {
      Context initCtx = new InitialContext();

      try {
        poolClass = (String)appServerLookup(initCtx, POOL_ENV_URL, "pool-class");
      } catch (ClassCastException exception) {
        throw new ClassCastException("Couldn't convert value in key pool-class to String. " + exception.getMessage());
      } catch(NamingException exception) {
        log.info("Could not find key pool-class. Assuming normal appserver dbPool factory should be used.");
      }
    } catch(NamingException exception) {
      throw new DataLayerException("Couldn't create initial context.", exception);
    }

    ConnectionPoolFactory poolFactory = null;
    if(poolClass != null && poolClass.trim().equals("") == false) {
      try {
        // use custom pool
        log.info("Found information about custom dbPool factory. Trying to instanciate: " + poolClass);

        Class<?> poolClassClass = Class.forName(poolClass);
        try {
          poolFactory = (ConnectionPoolFactory)poolClassClass.newInstance();
        } catch (IllegalAccessException exception) {
          log.info("Exception was thrown when instanciating custom dbPool factory!", exception);
        } catch (InstantiationException exception) {
          log.info("Exception was thrown when instanciating custom dbPool factory!", exception);
        }
      } catch (ExceptionInInitializerError exception) {
        log.info("Exception was thrown when trying to find class for custom dbPool factory!", exception);
      } catch (ClassNotFoundException exception) {
        log.info("Exception was thrown when trying to find class for custom dbPool factory!", exception);
      } catch (LinkageError exception) {
        log.info("Exception was thrown when trying to find class for custom dbPool factory!", exception);
      }
    }

    if (poolFactory == null) {
      // default appserver pool
      log.info("Instanciating normal appserver pool.");
      poolFactory = new AppServerPoolFactory();
    }

    return poolFactory;
  }

}